﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using OpenExpressApp.MetaModel;
using System.Reflection;
using OpenExpressApp.MetaAttribute;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Input;
using OpenExpressApp.Module.View;

namespace OpenExpressApp.Module.WPF.Behaviors
{
    /// <summary>
    /// 这个对象从被附加的View中找出所有被选择的数据对象，回到目的View中。
    /// </summary>
    public class SelectViewBehavior : ViewBehavior
    {
        /// <summary>
        /// 目标View
        /// </summary>
        private ObjectView _destView;

        /// <summary>
        /// 目标属性和源属性匹配
        /// </summary>
        private Dictionary<string, string> _propertyMaps;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="destView">选择出来的数据，存储在这个目的View中。</param>
        /// <param name="propertyMaps">
        /// 目标属性和源属性匹配
        /// Key:目标属性名
        /// Value:源属性名
        /// </param>
        public SelectViewBehavior(ObjectView destView, Dictionary<string, string> propertyMaps)
        {
            if (destView == null) throw new ArgumentNullException("destView");
            if (propertyMaps == null) throw new ArgumentNullException("propertyMaps");

            this._destView = destView;
            this._propertyMaps = propertyMaps;
        }

        /// <summary>
        /// 监听View的MouseDoubleClick事件，并加入一个选择按钮。
        /// 都进行select操作
        /// </summary>
        protected override void OnAttach()
        {
            var btnSelect = new Button() { Content = "选择" };
            (this.View as WPFObjectView).ToolBar.Items.Add(btnSelect);
            (this.View as WPFObjectView).ToolBar.Visibility = Visibility.Visible;

            //Click和MouseDoubleClick的时候，都执行Select方法
            btnSelect.Click += btnSelect_Click;
            (this.View as ListObjectView).MouseDoubleClick += View_MouseDoubleClick;
        }

        /// <summary>
        /// 点击按钮，选择操作完毕。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSelect_Click(object sender, RoutedEventArgs e)
        {
            this.SubmitSelection();
        }

        /// <summary>
        /// 双击视图，选择操作完毕。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void View_MouseDoubleClick(object sender, EventArgs e)
        {
            this.SubmitSelection();
        }

        /// <summary>
        /// 选择操作结束，提交选择的数据。
        /// </summary>
        private void SubmitSelection()
        {
            //这里，destView是DetailsView，就会有问题吧？？
            IBindingList items = this._destView.Data as IBindingList;
            if (items == null) throw new ArgumentNullException("items");

            //找到第一个CanAdd方法
            MethodInfo canAddMethod = _destView.Data.GetType().GetMethods()
                .FirstOrDefault<MethodInfo>(x => x.HasMarked<CanAddMethodAttribute>());

            //找到containsMethod的所有Pscal参数
            IList<string> paramNames = null;
            if (canAddMethod != null)
            {
                //标记了的第一个方法。
                paramNames = new List<string>();

                //把所有参数的第一个字母变为大写，并加入到paramNames中
                foreach (ParameterInfo parm in canAddMethod.GetParameters())
                {
                    string str1 = parm.Name.Substring(0, 1);
                    string str2 = parm.Name.Substring(1, parm.Name.Length - 1);
                    paramNames.Add(str1.ToUpper() + str2);
                }
            }

            //每一个已经选中的对象
            foreach (var src in this.View.GetActiveObjects())
            {
                if (canAddMethod != null)
                {
                    IList<object> parmsValue = new List<object>();
                    foreach (string parmName in paramNames)
                    {
                        //上面得到的参数名，就是属性名。
                        parmsValue.Add(src.GetPropertyValue(parmName));
                    }

                    //使用所有属性值来调用这个方法，如果返回false，则添加
                    var result = canAddMethod.Invoke(items, parmsValue.ToArray());
                    if (Convert.ToBoolean(result) == false)
                    {
                        this.AddObject(src, items);
                    }
                }
                else
                {
                    this.AddObject(src, items);
                }
            }
        }

        /// <summary>
        /// 为dests添加一个新的对象
        /// </summary>
        /// <param name="src"></param>
        /// <param name="dests"></param>
        private void AddObject(object src, IBindingList dests)
        {
            // 用dests添加一个新的对象
            object newObject = dests.AddNew();

            //设置父属性的值
            newObject.SetPropertyValue(_destView.GetKeyToParentView(), _destView.Parent.CurrentID);
            newObject.SetPropertyValue(_destView.GetKeyObjToParentView(), _destView.Parent.CurrentObject);

            //并根据propertyMaps中的属性对应，把属性赋值给这个新的对象
            foreach (KeyValuePair<string, string> pair in _propertyMaps)
            {
                newObject.SetPropertyValue(pair.Key, src.GetPropertyValue(pair.Value));
            }
        }
    }
}
